#include <string>
#include "typedefs.hpp"
#include "tests/PruebaCompresor.h"
#include "tests/PruebaArchivoAuxiliar.h"
#include "tests/PruebaBitStream.h"
#include "tests/PruebaArchivoPunteros.h"
#include "tests/PruebaArchivoFrontCoding.h"
#include "tests/PruebaArchivoIndice.h"
#include "tests/PruebaArchivoUtils.h"
#include "tests/PruebaHuffman.h"
#include "consulta/Consulta.h"
#include "preproceso/OrganizadorTextos.h"
#include "preproceso/archivos/ArchivoAuxiliar.h"
#include "commons/excepciones/NoExisteArchivoException.h"
#include "commons/InfoRepositorioActual.h"
#include "general/Indexador.h"

#include <sys/stat.h>   // Para stat().
#include "preproceso/Merger.h"
#include "preproceso/archivos/ArchivoDocumentos.h"
#include  "commons/Huffman.h"
#include "parsing/ParseadoQuery.h"
#include "parsing/ParserString.h"
using namespace std;

void correrTests() {
	//no se como definir clases estaticas, dsps lo cambio.

	int cont = 0;
	cout << "PRUEBAS A CORRER : 8" << endl;
	PruebaCompresor pr;
	pr.runSuit();
	cont++;
	PruebaArchivoAuxiliar pr2;
	pr2.runSuit();
	cont++;
	PruebaBitStream pr3;
	pr3.runSuit();
	cont++;
	PruebaArchivoPunteros pr4;
	pr4.runSuit();
	cont++;
	PruebaArchivoFrontCoding pr5;
	pr5.runSuit();
	cont++;
	PruebaArchivoIndice pr6;
	pr6.runSuit();
	cont++;
	PruebaHuffman pr7;
	pr7.runSuit();
	cont++;
	PruebaArchivoUtils pr8;
	pr8.runSuit();
	cont++;

	// si falla algo este contador ni se va a a imprimir, es una mala idea esta, pero es para no hardcodear los dos valores;
	cout << endl;
	cout << "&&&&&&&&&&&&&&&&&&& PRUEBAS CORRIDAS: " << cont << " &&&&&&&&&&&&&&&&&&&&&&" << endl;
}

void appe(std::string s) {
	cout << s << endl;
}

void imprimirEntrada(EntradaAuxiliar * a) {
	cout << a->getTermino() << ": " << "Doc: " << a->getDocumento() << " Posiciones: ";
	list<EnteroLargo>::iterator it;
	for (it = a->getPosiciones().begin(); it != a->getPosiciones().end(); ++it) {
		if (it == a->getPosiciones().begin()) {
			cout << *it;
		} else {
			cout << "," << *it;
		}
	}
	cout << endl;
}

// Agarro el string de la query, y lo paso a la clase que lo procesa
// Devuelvo una lista con los terminos ya procesados
void procesoString(list<string> &listaTerminos, string S) {
	ParserString pars(S);
	ParseadoQuery x;
	while (pars.hasNext()) {
		ParseadoQuery x(pars.next());
		listaTerminos.push_back(x.getTermino());
	}
}

// En caso de ser una operacion de proceso de indices sera 1;
// En caso de ser una busqueda sera 0
// EN caso de ser error -1
int procesoParametros(string& repositorio, string& ruta, list<string> &terminosQuery, int argc, char*argv[]) {
	string S;
	int tipoProceso = 0;
	int i;
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-r") == 0) {
			// La primer cadena despues del -r sera el repositorio
			repositorio = argv[++i];
		} else if (strcmp(argv[i], "-i") == 0) {
			// La primer cadena despues del -i sera el repositorio
			repositorio = argv[++i];
			// La primer cadena despues del -i sera la ruta
			ruta = argv[++i];
			tipoProceso = 1;
		} else if (strcmp(argv[i], "-q") == 0) {
			// Guardo el string del query y lo proceso obtenieno la lista
			S = argv[++i];
			procesoString(terminosQuery, S);
		} else {
			cout << "Parametro desconocido" << endl;
			return -1;
		}

	}
	return tipoProceso;
}

void asegurarDirectorio(FileName path) {
		struct stat status;
		stat(path, &status);
		if (!(status.st_mode & S_IFDIR)) {
			cout << "CREANDO DIRECTORIO DE INDICES..." << endl;
			mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
//			perror("no funca");
	}
}

int main(int argc, char *argv[]) {
	// ruta donde se guarda el indice
	char arg1[20];
	char exepath[254 + 1] = { 0 };
	sprintf(arg1, "/proc/%d/exe", getpid());
	::readlink(arg1, exepath, 1024);
	string path = string(exepath);
	unsigned found = path.find_last_of("/\\");
	path = path.substr(0,found);
	path.append("/Indices");
//	path = "/home/jonathan/Escritorio/datos/Indices";
	asegurarDirectorio(path.c_str());
	FileName RUTA_SALIDA = path.c_str();

	//	FileName RUTA_SALIDA = "/home/jonathan/Escritorio/datos/workspace/Indice";
	// En caso de ser una operacion de proceso de indices sera 1;
	// En caso de ser una busqueda sera 0
	// EN caso de ser error -1
	int tipoOperacion;
	string repositorio, ruta;
	list < string > terminosQuery;
	tipoOperacion = procesoParametros(repositorio, ruta, terminosQuery, argc, argv);
	InfoRepositorioActual::Instance()->setTamanioBloqueFC(5000);
	switch (tipoOperacion) {
	case 0:
		//Operacion de Busqueda
	{
		list < string > *query = &terminosQuery;
		ArchivoDocumentos archdoc(repositorio.c_str(), RUTA_SALIDA, fstream::in);
		archdoc.recuperarDatos();
		ArchivoIndice arch(RUTA_SALIDA, repositorio.c_str(), fstream::in);
		ArchivoIndice* parch = &arch;
		Consulta consulta(parch);
		Termino* termino = consulta.consultar(query);
		if (termino == 0) {
			cout << "No se encontraron resultados" << endl;
		} else {
			if (terminosQuery.size() > 1)
				cout << "La frase: ";
			else
				cout << "El termino: ";
			cout << termino->getCaracteres() << endl;
			cout << "Aparece en los siguientes documentos: " << endl;
			list<Documento*> docs = *(termino->getDocumentos());
			list<Documento*>::iterator ite;

			for (ite = docs.begin(); ite != docs.end(); ++ite) {
				cout << archdoc.getDocumento((*ite)->getNumero()) << endl;
			}
		}
	}
		break;
	case 1:
		// Operacion de Proceso de Indices
	{
		Indexador index(ruta.c_str(), repositorio.c_str());
		index.procesar(RUTA_SALIDA);
	}
		break;
	default:
		// Parametros incorrectos
		cout << "parametros incorrectos" << endl;
	}

	return 0;
}
;
